chore(pm): the queue guard reads its record recognisers from record-recognisers.mjs; check-clause2-carriers.mjs is deleted - #19803
Conversation
…, moved out of check-clause2-carriers Step 4 of ruling record 5770886272 (letter B). The readers the queue guard's Tier S leg imports — locateReviewOfRecord, deliveredCardNumber, servedTierStands, isModelIdentifierToken, REVIEW_OF_RECORD_THREADS / REVIEW_OF_RECORD_LOCATION, CONTRACT_REVIEW_TIER_NAME, unexplainedPathsBetween — and the record template with its --template CLI, moved verbatim with their docblocks into their own module. The self-test cases that pin these readers move with them; the ones that read the retired rows do not. Nothing imports this file yet; the guard is re-pointed in the next commit. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…ointers at record-recognisers.mjs - check-governed-queue-guard.mjs: RECOGNISER_SOURCES.tier is now './record-recognisers.mjs' (still a LAZY import; the no-top-level-await pin and the renamed-source pin follow), and its docblocks name the new file. - lint.yml + package.json: the step that ran check-clause2-carriers' self-test is retargeted, not added beside — `pnpm check:pm-record-recognisers`. - references/contract-review.md: the two `--template` pointers name `node scripts/pm/record-recognisers.mjs --template`, each wrapped once to stay under the 120-byte line cap (24 -> 26 of 60 lines). - Present-tense prose that named the old file as a live importer, location or message is re-pointed: clause2-line, check-expected-skips, check-closing-target-claim, check-adr-0087-registration, check-half-states (one runtime sentence included), check-widening-tells (its usage refusal). Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…g record 5770886272 Nothing imports it any more: the queue guard's lazy import reads record-recognisers.mjs, and the lint step runs that file's self-test. Gone with it, not re-homed: the retired `--pair` scan and its readers (derivePairs, the C1-C9 rows, pairRows, the read-path ladder, the input record), the claim readers no live importer used, the local copy of the retired label constant, and the self-test battery of those parts. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…ep4-record-recognisers-module
…ep4-record-recognisers-module
Contract reviewServed-tier: ① Derived judgmentsRendered in-seat by the skills seat 1 session at the served tier the maintainer named (ruling record 5771798588; 「契约复审继续用 fable 不变」 5788482806 of this date). The contract is ruling B on #19061 (5770886272, 三层归一), step ④ as named on the step-③ Release 5789425558 and the claim 5789522248: the record recognisers and
② Semver levelNone — no release. ③ Boundary flags
Implemented-by: VERDICT: PASS |
|
Standing down on the queue refusal — this PR lands only by 人工直合, not through the merge queue. What was measured (REST + the job log, read this act):
The one door this PR has — as the guard's own remedy text states it and as #19344 (maintainer item 6) narrowed it: the Merge button's bypass-rules option (「Merge without waiting for requirements to be met」), offered only while ruleset Seat position: the 四件套 is complete (ACCEPT 5790743219 on #19061, |
…H / Tier S (objectstack-ai#19820) Fixes objectstack-ai#19146 Clause-②: no ## What this PR does Re-keys the four remaining PM-charter lines that still spelled the retired 规则层 / 事实层 two-layer split to the register's own two tiers — **Tier S** (every governed path under `.claude/**`; the owning seat lands it through the queue on a `## Contract review` PASS record) and **Tier H** (every other governed surface; draft until an authorized APPROVED review) — exactly as `.claude/agents/os-dev.md` :286–:287 already spells them since PR objectstack-ai#19802 (`4a12ac0c4`). The wording model is ruling B on objectstack-ai#19061 (comment 5770886272) as `os-dev.md` carries it; this delivery completes the remainder named by the seat's Release 5790724014 on the card. Vocabulary only: each rule's meaning is unchanged, and no line is added or removed in any file. ### The four lines, before and after (bytes against the 120-byte cap) 1. `.claude/skills/pm-dispatch/SKILL.md` :187 (118 B → 116 B) - before 「- 路径面命中规则层 ⇒ ACCEPT 换终局四件套,混合 diff ⛔ 不按比例判;要拆让 dev 单独开 PR。」 - after 「- 路径面命中 Tier H ⇒ ACCEPT 换终局四件套,混合 diff ⛔ 不按比例判;要拆让 dev 单独开 PR。」 - 规则层 here meant a Tier H path: one Tier H path hit switches ACCEPT to the terminal four-set; the mixed-diff clause is untouched. 2. `.claude/skills/pm-dispatch/SKILL.md` :188 (111 B → 110 B) - before 「- 改动 >5000 行(含生成物)同换终局四件套,⛔ 无事实层例外;读数 = PR additions+deletions。」 - after 「- 改动 >5000 行(含生成物)同换终局四件套,⛔ 无 Tier S 例外;读数 = PR additions+deletions。」 - 事实层 here meant Tier S: the size limb has NO Tier S exception — the rule the queue guard applied to PR objectstack-ai#19803 today; only the word moved. 3. `.claude/skills/pm-dispatch/references/landing-operations.md` :58 (117 B → 115 B) - before 「- 转 ready/入队前跑 `check-governed-merges.mjs --pr N`:受管面照两层;>5000 行(含生成物)照规则层。」 - after 「- 转 ready/入队前跑 `check-governed-merges.mjs --pr N`:受管面照两层;>5000 行(含生成物)照 Tier H。」 - 规则层 here meant the Tier H terminal (四件套, a human merge); :59–:60 beside it already spell Tier S / Tier H. 4. `.claude/skills/pm-dispatch/references/lanes/skills.md` :17 (113 B → 111 B) - before 「- 规则层受管 PR 恒 draft 等维护者的字;flip 或 arm 前跑 `check-governed-merges --test` 带路径。」 - after 「- Tier H 受管 PR 恒 draft 等维护者的字;flip 或 arm 前跑 `check-governed-merges --test` 带路径。」 Line counts unchanged: SKILL.md 319 / 319 (headroom 0), landing-operations.md 101 / 101 (headroom 0), lanes/skills.md 32 / 33 (headroom 1). Widest edited line 116 B. The edit was applied by an anchor-counted replace (each old line asserted to occur exactly once, each new line read back exactly once, line count asserted equal), not by a regex tool's exit code. ### Premise and concurrency, measured - H1 on `origin/main` `6eaa0f4a8`: `git grep -n -E '规则层|事实层' origin/main -- .claude/skills/pm-dispatch/ .claude/agents/` → exactly the four lines above, nothing else. After the edit: 0 hits on that surface, and the card's own acceptance grep (`grep -rn 事实层 .claude AGENTS.md`) → 0 hits. - The only remaining whole-tree hits are `scripts/pm/check-governed-queue-guard.mjs` :236 / :240, inside a verbatim maintainer-ruling quotation that the file's own header marks as reproduced rather than paraphrased — not a spelling of the retired split, not on this surface, not edited. - H3 at PR-open time: all 17 open PRs' file lists read over REST (PR objectstack-ai#17076's 773 / 773 files paged to a short page) — none touches any of the three files. - Register: `node scripts/pm/check-governed-merges.mjs --test` on the three paths → `GOVERNED — Tier S(席内达档复核落地)`, exit 3. ### Landing — Tier S `.claude/**` is on the register as Tier S. This PR is opened as a DRAFT and stays draft: the owning seat renders the `## Contract review` record for the current head and lands it through the queue once every check is green. No seat approves it and no maintainer click is waited for. objectstack-ai#19803 is not addressed here; it is cited only as the guard's reading of the size limb. ### Gates at head `1282c7efc` `1282c7efc` = `8f7e56a6c` (the four-line commit) merged with `origin/main` `0e06f3b5d`; the three-dot delta vs `origin/main` is exactly the three files, +4 −4. `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no paths; changeset from the merge base) derived 20 families, the same list at `8f7e56a6c` and at `1282c7efc`. Every command was run on `1282c7efc` with its exit captured before any pipe (stdout+stderr redirected to a file, the exit read on the next statement): 19 × exit 0, 1 × exit 3. Reconciliation `--ran` → `20 derived famil(ies) accounted for — 19 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)`, exit 0. - `check:pm-skill-ratchet` exit 0 — `.claude/skills/pm-dispatch/SKILL.md is 319 lines (ceiling 319; headroom 0)`, `widest table row is 342 bytes (pin 342; headroom 0)`; `references/landing-operations.md is 101 lines (ceiling 101; headroom 0)`; `references/lanes/skills.md is 32 lines (ceiling 33; headroom 1)`. Same readings before the edit at `6eaa0f4a8`. - `check:skill-frame-sync` exit 0 — the one declared copy of the decision frame is internally coherent, 4 axes; the frame block (SKILL.md :241–:261) is untouched. - `check:pm-skill-id-lint` exit 0 (34 files clean) · `check:nul-bytes` exit 0 · `check:doc-authoring` exit 0 (16192 customer-facing strings clean) · `check:pm-governed-prose` exit 0 (2 surfaces name all 6 registered governed surfaces) · `check:pm-expected-skips` exit 0 (99 cases). - `check:pm-governed-merges` exit 0 (441 assertions) · `check-governed-queue-guard.mjs --self-test` exit 0 (279 cases) · `check-harness-current.mjs --self-test` exit 0 (26 cases) · `check-closing-keyword-parity.mjs` self-test 40 assertions, sweep OK (3 parsers agree on all 9 keywords) · `check:watch-hint-literal` exit 0 (71 declarations) · `check:gitlink-declared` exit 0 (36 assertions). - `check-comment-mask-corpus.mjs` exit 0 (7020 files, 0 disagree) · `check:agent-test-spelling` exit 0 (0 violations) · `check:cross-package-test-inputs` exit 0 (255 self-test cases; 29 packages, all declared) · `check:driver-memory-census` exit 0 · `check:refd-timer-probe` exit 0 (11 cases). - NOT MEASURED: `pnpm --filter @objectstack/lint run check:doc-formula-expressions` exit 3 = `PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built`. This diff touches no package, so no ① build closure is owed, and that family's population (docs formula expressions) is disjoint from the three paths. No package is touched: no package build or test, no verify-lock slot taken. `skills/**` (the published catalog) is untouched, so no whole-file / whole-package token readings are owed. No changeset: `.claude/**` publishes nothing from any package's `files[]` ⇒ `skip-changeset`. ## 维护者速读(草稿) - **改了什么**:PM 派发技能(`pm-dispatch`)里还剩四行沿用已废弃的「规则层 / 事实层」两层叫法(SKILL.md 两行、落地操作一行、skills 车道一行),本 PR 把它们改成登记表现行的 Tier H / Tier S 词汇,与 `os-dev.md` 已落地的写法一致。只换词,不换规则:每条规则的意思、每个文件的行数都不变。 - **为什么改**:每个席位每轮都读这几行;词汇与登记表、AGENTS.md 第 14 条不一致,席位会按一个已不存在的分层去判断 PR 该怎么落地——例如把「无事实层例外」读成一条无人能对上号的例外。 - **风险与代价(含回滚)**:零功能改动,不触任何发布包;派生门禁 20 族 19 绿、1 未测(formula 包未构建,与本 diff 无关,CI 会跑)。回滚即还原四行,无迁移、无数据影响。 - **席位意见**:(待席位填写) - **你要做的**:无需操作;`.claude/**` 属 Tier S,由席位在契约复核 PASS 记录上入队落地。 ## Acceptance notes - noted, not filed: `scripts/pm/check-governed-queue-guard.mjs` :236 / :240 still carry 事实层 / 规则层 inside the verbatim maintainer-ruling quotation the file reproduces on purpose — immutable, and not a live instance of the retired split. --- _Generated by [Claude Code](https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc)_ Co-authored-by: Claude <noreply@anthropic.com>
…y the gate-family selector (objectstack-ai#19812) Fixes objectstack-ai#19753 Clause-②: no ## Ruling (not reopened here) The maintainer's 「同意 A′」, recorded by triage in comment 5790385022 on objectstack-ai#19753: `check:migration-registry` becomes a step inside the required `Lint & Repo Gates` job. It runs only when a change touches `packages/spec/src/migrations/**`, and it hangs on the existing gate-family selector. It is not a separate `paths:`-filtered required check, which would never report on unrelated PRs. ## Design - **`scripts/ci/select-gate-families.sh`**: adds the new family `migration_registry`. It comes first in `FAMILIES` because its step is the earliest scoped step in the job. Its read-set is everything the gate reads: - `packages/spec/src/migrations/**`: the entries and the generated `registry.ts`. An edit to either side alone is the drift the gate reports. - the generator, `packages/spec/scripts/build-migration-registry.ts`. - `packages/spec/package.json`, which pnpm resolves the script through. - `packages/spec/tsconfig.json`, which tsx loads. It extends the root tsconfig, and root config already runs every family. Every other path skips. A skip here is a ratchet-grade claim: no changed path is one the gate reads. The selector's fail-open branches still run this family like every other one. Those branches are: an unscoped event (push on main, the hourly run), a missing or unresolvable base, a failed or empty diff, an unclassified path, and a deletion or rename. - **`.github/workflows/lint.yml`**: adds one step, `Migration registry matches its entry files`, with `if: steps.gate-families.outputs.migration_registry != 'skip'` and `run: pnpm --filter @objectstack/spec check:migration-registry`. It sits right after `ADR anchors` because the job's ordering note puts cheap gates first. The selector step's comment now counts TEN families. The region PR objectstack-ai#19803 edits (hunk at 1247) is untouched. - **`scripts/ci/select-gate-families.selftest.sh`**: - The fixture gains the read-set and its nearest neighbours. - 12 new cases: entry M/A/D, a stray non-TS file in an entry dir, `registry.ts`, the generator, the spec manifest and tsconfig, a sibling spec script, a spec source outside the tree, a lookalike directory, and a pull_request feature branch. - Every count line that moved is updated. The one `expect_all_run` that became false (`scripts/helper.mjs`) now lists the nine families it runs. - A new `pin_step` for the new step. - The floor rises from 42 cases / 220 checks to 56 / 293. - **Rosters**: none needed updating. Only the selector, its self-test and `lint.yml` name family ids. `check:migration-registry` was already classified in `packages/spec/scripts/check-generated.ts`. ## On `main` first (ruling item 3) `pnpm --filter @objectstack/spec check:migration-registry` at `a5afe382ba` exited 0 with `src/migrations/registry.ts is current (232 semantic, 207 retired-key, 183 retired-def)`. The registry is **not stale**, so `registry.ts` is untouched and this PR has no changeset: nothing published changes. ## Duration (ruling item 4) Wall clock of the exact step command, in a 4-core container: - 1.37 s when the machine was idle. - 1.47 to 1.62 s over 5 runs at load ~6. It needs no build: tsx reads one directory and splices text. When a PR's diff is outside the read-set, the step is skipped and costs about 0 s. ## Verification (head `e1825aabbf`) - **Selector self-test**: base `a5afe382ba` passes 44 cases / 228 checks. Head passes 56 cases / 293 checks. - **Selector on the real tree** (scratch clone, `merge_group`): - An entry edit gives `run migration_registry reads packages/spec/src/migrations/entries/semantic/17.action-descriptor-is-async-retired.ts (M, workspace)`. - A docs-only commit gives `skip migration_registry no changed path is in its read-set`. - An unresolvable base gives `run migration_registry merge group base ... unresolvable`. - **Lit test of the gate** (scratch clone): 1. On the clean tree it exits 0. 2. With one entry's prose edited and the registry not regenerated, it exits 1: `registry.ts is stale`. The edit had landed: in the entry, the old text went from 1 copy to 0 and the new text from 0 to 1, while the registry still carried 0 copies of the new text. 3. After `gen:migration-registry` rewrote one line, it exits 0. - **Ablations** (scratch clone; each one restored with the blob equal to HEAD and `git diff HEAD` empty): - Remove the migration-tree arm: 16 FAIL. - Spell the `if:` as `== 'run'`: 4 FAIL. - Run base's selector and workflow under head's self-test: 139 FAIL. - Drop `--filter` from the step: the pin FAILs. - **Derived gates** (`dispatch-gates --repo objectstack-ai/objectstack --commands`, 51 commands) plus `check:issue-citations` (self-test and diff-scoped) plus the gate itself: - All exited 0 except `pnpm check:type-check-debt`, which exited 3 with `PREREQUISITE NOT MET` (it needs the whole `packages/*` closure built). That result is NOT MEASURED, not red. The diff touches no package source or tsconfig, so it is left to CI. - `pnpm check:pm-dispatch-gates` was still running when this PR opened. Its verdict is in the `os-dev-report` on objectstack-ai#19753. - **Hygiene**: 0 control bytes and 0 model identifiers in the added lines. Both scans fire on a lit control. - **This PR's own `Lint & Repo Gates` run**: the new step should read **skip**. This diff touches only `.github/workflows/` and `scripts/ci/`, and neither is in the read-set. So the first CI execution of the step on the real tree is the push-on-main run after merge, where every family runs. The exact command was run locally, and the self-test pins it. ## Acceptance notes - Noted, not filed: AGENTS.md "Touched `packages/spec`?" says every spec generated-artifact gate lives in `TypeScript Type Check`. That was already untrue for this gate, which ran nowhere, and after this PR it lives in `Lint & Repo Gates`, scoped. AGENTS.md is a governed surface. Owner: none. - Landing: this touches `.github/workflows/**`, so per triage, seat auto-merge answers 422 and the PR needs a human merge. --- _Generated by [Claude Code](https://claude.ai/code/session_01UDXER3sdqfeVYpEWZs5mZx)_ Co-authored-by: Claude <noreply@anthropic.com>
Fixes #19061
维护者速读(草稿)
Governed Surface Queue Guard)放行.claude/**时读## Contract review记录所用的识别器,以及席位照抄的--template记录模板,从 10,220 行的scripts/pm/check-clause2-carriers.mjs原样搬进新文件scripts/pm/record-recognisers.mjs(连同钉住它们的自测用例),然后删除旧文件。守卫改为懒加载新文件;lint.yml里原先跑旧文件自测的那一步改指新文件(不是新增门禁);contract-review.md两处--template指针改写为新命令。--pair扫描、C1–C9 行、认领读取器)早已退役、无人调用。席位意见
建议批准并合并;这是裁决 B(三层归一)的最后一步,做的全是减法。 一万行的
check-clause2-carriers.mjs删掉,队列守卫懒加载的那几个记录识别器和--template原样搬进 1,324 行的record-recognisers.mjs(含它们自己的 110 个自测例);守卫指向新文件,懒加载没动(dev 用消融证明一改成即时加载就死锁,所以懒加载必须留);--template输出 40 行里后 39 行逐字节相同,只有第一行改名。lint 工作流那一步是改指向不是新增,步数不变;contract-review.md两处指针跟着改,行数 24 → 26,天花板 60。席位在新 worktree 上重跑:识别器自测 110、守卫自测 279、半态自测 4897、十个门禁全 0。之所以要你点合并:改动行数 11,684 超过 5,000 的人工合并线(删除也计数),不是档位问题。合并即Fixes #19061,四步全部落地。复核记录:PR 评论 5790479344(PASS,在席按服务档渲染);ACCEPT 在卡 #19061。CI 读数:36 latest-per-name check runs — 30 success, 6 skipped, 0 in progress, 0 other。## Contract reviewPASS 记录、所有检查全绿之后,请您手动点合并 —— 超 5,000 行的 PR 按规则只能人工合并,队列守卫的 size 腿会拒绝入队。Clause-②: no
What this does
Ruling record 5770886272 (letter B), its last step, named on Release 5789425558. Four commits, one per class, so a reviewer can bisect:
a4a16863e— the module.scripts/pm/record-recognisers.mjsholds exactly whatcheck-governed-queue-guard.mjsreads from the old file — throughloadRecordRecognisers(locateReviewOfRecord,deliveredCardNumber,servedTierStands,isModelIdentifierToken,REVIEW_OF_RECORD_THREADS,REVIEW_OF_RECORD_LOCATION) and in its self-test throughRECOGNISER_SOURCES.tier(CONTRACT_REVIEW_TIER_NAME,unexplainedPathsBetween) — plus what those are built from (readServedTier, the stamp control, the regeneration carry,REVIEWED_BY_LINE,DELIVERY_EVIDENCE_PRECEDENCE) and the record template (contractReviewTemplateLines,contractReviewRecordLines,RECORD_TEMPLATE_PLACEHOLDERS, the two fences) with a--templateCLI. The code blocks are verbatim slices of the old file's blob at2cf9db7c4; ten docblock sentences that named a deleted function as live are corrected, each listed under Deviations. The self-test cases that pin these readers moved with them (110 cases, six batteries, roster floor and verdict handshake); the cases that read the retired rows did not.baa17b116— the re-points. The guard'sRECOGNISER_SOURCES.tieris./record-recognisers.mjs(still a LAZY import from a function body), its renamed-source pin and docblocks follow. Thelint.ymlstep that ran the old self-test is retargeted topnpm check:pm-record-recognisers— ⛔ not a gate added beside it.references/contract-review.md:13 / :19 now point atnode scripts/pm/record-recognisers.mjs --template. Present-tense prose that named the old file as a live importer, location or message is re-pointed (list below).81b3469d6— the deletion.scripts/pm/check-clause2-carriers.mjs(10,220 lines) is removed, and with it, not re-homed: the--pairscan and its readers (derivePairs, C1–C9,pairRows, the read-path ladder, the input record), the claim readers no live importer used, the local copy of the retired label constant, and the self-test battery of those parts.origin/main(the last at98d83361d); neither touches a file this PR edits.Measured premises
2cf9db7c4the guard'sRECOGNISER_SOURCES.tierread./check-clause2-carriers.mjs.git grepfor a statement-shapedimport/fromof the file: zero hits. With the file deleted in the worktree before any re-point, 27scripts/pm/*.mjs --self-testruns (every one butdispatch-gates.mjs, whose battery takes about 12 minutes, andcheck-dispatch-gates.mjs) pluscheck-governed-merges.mjs --testandfirst-party-closure.mjswere compared with the same runs with the file present: the ONLY exit that moved was the guard's self-test, 0 → 1 (ERR_MODULE_NOT_FOUND). Both omitted batteries passed on the final tree (Tests). The one other consumer was CI's own invocation (lint.yml:1267through thecheck:pm-clause2-carriersalias), retargeted here.record-recognisers.mjsplanted in the guard exits 13 withDetected unsettled top-level await at .../check-half-states.mjs:9765; restored byte-identical (bloba2fd67afc6bb== HEAD,git diff HEADempty). But a freshnode -eimport of the new module DOES load the guard: it importscheck-half-states.mjsfor the record readers anddeliveryEvidence, and that file's module-scope top-level await imports the guard — exactly as the old file did. Avoiding it would mean restatingcheck-half-states.mjs' readers, which the module's own rule forbids; this is why the guard's import stays lazy.check:first-party-closuredoes not exist:scripts/first-party-closure.mjsis a library with no CLI; its consumers' self-tests ran (check-adr-0087-registration441 assertions,check:objectui-changeset).origin/mainmoved2cf9db7c4→98d83361dduring this work and touched none of these files.--template, before and after40 lines both times; lines 2–40 byte-identical. Line 1 names the tool that prints it —
record-recognisers --templateinstead of the deletedcheck-clause2-carriers --template.Tests — at HEAD
5c24980efnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths) derived 85 commands at5c24980ef, byte-identical to the list derived atbfe5b9917before the last merge; all 85 were run on5c24980ef, each exit captured before any pipe, and--rananswers✓ dispatch-gates --ran: 85 derived famil(ies) accounted for — 82 run, 3 NOT-MEASURED (3 DERIVED from a recorded exit 3).dist/output, with no workspace package built here (74 of 78 build tasks are cache misses):check:dual-build-cjs-loads,check:lean-entry-closureandcheck:type-check-debtexit 3PREREQUISITE NOT MET;check:dts-closureandcheck:sourcemap-no-sources-contentexit 0 but swept only the 4 packages built forcheck:doc-formula-expressions(formula, lint and their closure), a partial population and not a measurement of the whole. This diff changes no workspace package's source, manifest or build — only the private root package'sscriptsmap — so none of their verdicts can move; CI builds the closure and runs them.pnpm check:pm-record-recognisers→✓ record-recognisers self-test: 110 cases pass. Ablations throughscripts/ablation-replace.mjs, each landed on disk and restored to the HEAD blob:servedStampsHoldmade to accept any control → 3 of 110 red;DELIVERY_EVIDENCE_PRECEDENCEreordered → 2 of 110 red.node scripts/pm/check-governed-queue-guard.mjs --self-test→✓ check-governed-queue-guard self-test: 279 cases pass(279 before the change too).pnpm check:pm-dispatch-gates→✓ dispatch-gates self-test: 1905 cases pass.·pnpm check:pm-half-states→ 4897 cases ·pnpm check:pm-widening-tells→ 525 ·pnpm check:pm-expected-skips→ 99 ·pnpm check:closing-target-claim→ 105 ·check-changeset-no-major --self-test→ 339 ·check-adr-0087-registration --self-test→ 441 ·check-self-test-wired→every one of the 229 script(s) CI runs that ship a --self-test has that self-test run by CI·pnpm check:pm-skill-ratchet→contract-review.md is 26 lines (ceiling 60; headroom 34), every line at most 120 bytes (measured widest 118) ·pnpm check:skill-frame-sync,pnpm check:doc-authoring,pnpm check:declared-population-live,pnpm check:nul-bytes,check:doc-formula-expressions(after building formula and lint under the verify lock) → exit 0.eslint.config.mjs'sfiles: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']object minusNEVER_LINTED, which coversscripts/**;eslint --no-inline-config --format jsonover the 8 changed.mjsfiles reports 8 files, 0 errors, 0 warnings; the config enables no type-aware linting (--print-configshowsparserOptionsofecmaVersionandsourceTypeonly), so the diff cannot move the verdict of any file it does not touch.node scripts/pm/check-governed-merges.mjs --testover the three-dot path list → GOVERNED, Tier S (contract-review.mdis the one register hit).Deviations
--self-test, and the lint step is RETARGETED, not removed. The moved docblocks cite pins ("the self-test drives THIS function's output", "a MIRROR, so the self-test MEASURES it", "the cross-tool pin in this file's self-test"); moving the docblocks without those pins would have left them false, and the kept readers would have lost their unit cases. What moved is only cases that exercise a function this file owns.--templateline 1 names the new tool (above) — the dispatch asked for the old output exactly; a banner naming a deleted file is the one line changed.references/contract-review.mdgrows 24 → 26 lines: each re-pointed line is wrapped once, because the new spelling would push both past the 120-byte line cap (they were 119 and 104 bytes). No other line's text changed.scripts/first-party-closure.mjs:21 is unchanged: it is past-tense narration of the [finding] An accept-set narrowing owes a**BREAKING**banner incorebut not inplatform-objects— and the ADR-0087 classifier reads the banner #16421 measurement, not a closure list — the closure is computed from import edges, so the deletion needs no edit there.CLAUSE2_CORRECTION_KEY_LINEaside, the repo-shape example "below", the template round-trip reader, thederivePairs/ H31 askers, thereviewOfRecord"below", and the template banner.REVIEWED_BY_LINEis nowkeyLineRegex('Reviewed-by')(the same regex the deletedAUTHORSHIP_KEY_LINESbuilt; pinned equal by source in the self-test).scripts/pm/clause2-line.mjs(its docblock described this very step as pending) and one runtime usage line inscripts/pm/check-widening-tells.mjs(--reporefusal named the deleted file as the convention's reader; it now namescheck-half-states.mjs). Incheck-half-states.mjsone runtime sentence drops its clause about the deleted reader.Acceptance notes
scripts/pm/check-widening-tells.mjs' docblock still narrates its only caller, the deleted--pair(the C5 row, an exit register "pinned in THAT file's self-test", the caller section). Left as history rather than rewritten; the tool now has no caller besides its own self-test. carrier: 承接者:无.check-skill-line-ratchet.mjs:437 / :483 (raise ledger),dispatch-gates.mjs:6799 (an import-edge measurement),check-changeset-no-major.mjs:1452 (a phrase attribution),check-half-states.mjs:1404 / :2740 / :24659, the twodocs/audits/census snapshots.CLAUSE2_VALUES/CLAUSE2_ARMSinclause2-line.mjs,bindingClosesCardincheck-half-states.mjs. Not touched.node scripts/pm/measurement-claim-triage.mjs --self-testexits 1 onorigin/main(UNTRIAGED scripts/check-dts-references.mjs:74); it is not wired into CI.Generated by Claude Code
Generated by Claude Code